package com.wugh.fast.module.mapper.util;

import com.wugh.fast.kernel.core.util.AopTargetUtils;
import com.wugh.fast.kernel.core.util.SpringContextHolder;
import com.wugh.fast.module.mapper.CommonMapper;
import org.apache.ibatis.binding.MapperProxy;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.Collection;
import java.util.Optional;

/**
 * 说明: mapper工具
 *
 * @author wugh
 * @date 2019-01-29 11:42
 */
public class MapperUtils {

    private static Field mapperInterface = null;

    /**
     * 获取MapperProxy中mapperInterface属性对象
     *
     * @return
     */
    public static Field getMapperInterface() {
        if (mapperInterface == null) {
            synchronized (MapperUtils.class) {
                if (mapperInterface == null) {
                    Field mapperInterface;
                    try {
                        mapperInterface = MapperProxy.class.getDeclaredField("mapperInterface");
                    } catch (NoSuchFieldException e) {
                        throw new RuntimeException(e);
                    }
                    mapperInterface.setAccessible(true);
                    MapperUtils.mapperInterface = mapperInterface;
                }
            }
        }
        return mapperInterface;
    }

    /**
     * 根据实体类获取对应的mapper对象
     *
     * @param entityClass
     * @param <T>
     * @return
     */
    public static <T> Optional<CommonMapper<T>> getCommonMapper(Class<T> entityClass) {
        Collection<CommonMapper> mappers = SpringContextHolder.getApplicationContext().getBeansOfType(CommonMapper.class).values();
        for (CommonMapper mapper : mappers) {
            if (entityClass.equals(getEntityClass(mapper))) {
                return Optional.of(mapper);
            }
        }
        return Optional.empty();
    }

    /**
     * 根据mapper对象获取对应的实体类
     *
     * @param commonMapper
     * @param <T>
     * @return
     */
    public static <T> Class<T> getEntityClass(CommonMapper<T> commonMapper) {
        Object target = commonMapper;
        int time = 0;
        while (!(target instanceof MapperProxy)) {
            if (time > 10) {
                throw new RuntimeException("获取实体类失败");
            }
            try {
                target = AopTargetUtils.getTarget(target);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            time++;
        }
        Field mapperInterface = getMapperInterface();
        try {
            Class<?> mapperInterfaceClass = (Class<?>) mapperInterface.get(target);
            ParameterizedType genericInterface = (ParameterizedType) mapperInterfaceClass.getGenericInterfaces()[0];
            return (Class<T>) genericInterface.getActualTypeArguments()[0];
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        }
    }
}
